package py.com.alfa.escriba.web.services.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;

import py.com.alfa.escriba.exception.ErrorCode;
import py.com.alfa.escriba.exception.ServiceException;
import py.com.alfa.escriba.persistence.dao.PerfilDAO;
import py.com.alfa.escriba.persistence.dao.UsuarioDAO;
import py.com.alfa.escriba.persistence.dao.UsuarioPerfilDAO;
import py.com.alfa.escriba.persistence.dto.admin.FuncionalidadDTO;
import py.com.alfa.escriba.persistence.dto.admin.PerfilDTO;
import py.com.alfa.escriba.persistence.dto.admin.UsuarioDTO;
import py.com.alfa.escriba.persistence.dto.admin.UsuarioPerfilDTO;
import py.com.alfa.escriba.util.MD5;
import py.com.alfa.escriba.util.Utils;
import py.com.alfa.escriba.web.interceptor.InvocationContext;
import py.com.alfa.escriba.web.services.UsuarioService;

public class UsuarioServiceImpl implements UsuarioService{

	private UsuarioDAO usuarioDAO;
	private UsuarioPerfilDAO usuarioPerfilDAO;
	private PerfilDAO perfilDAO;
	private MD5 encriptador;
	
	public UsuarioServiceImpl(){
		encriptador = new MD5();
	}

	public void setUsuarioDAO(UsuarioDAO usuarioDAO) {
		this.usuarioDAO = usuarioDAO;
	}

	@Override
	public List<UsuarioDTO> listUsuario(InvocationContext ic) throws ServiceException {
		List<UsuarioDTO> usuarios =  usuarioDAO.listUsuario();

		return usuarios;
	}

	@Override
	public UsuarioDTO getUsuario(Long id, InvocationContext ic) throws ServiceException {
		if (id == null || id <= 0)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","id");

		UsuarioDTO usuario =  usuarioDAO.getUsuarioById(id);

		if (usuario == null)
			throw new ServiceException(ErrorCode.NO_DATA_FOUND,"usuario.notfound", id);
		
		//se cargan los perfiles no asignados al usuario
		usuario.setPerfilesNoAsignados(this.perfilDAO.listPerfilNoAsignados(usuario.getId()));

		return usuario;
	}
	
	@Override
	public UsuarioDTO validaUsuario(String usuario, String password, InvocationContext ic) throws ServiceException {
		if (usuario == null || usuario.isEmpty())
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","usuario");

		//se verifica la existencia del usuario
		UsuarioDTO usuarioDto =  usuarioDAO.getByUsuario(usuario);

		if (usuarioDto == null)
			throw new ServiceException(ErrorCode.NO_DATA_FOUND,"usuario.notfound", usuario);
		
		//se verifica la contraseña
		String clave =  encriptador.encriptaEnMD5(password);
		if(!clave.equalsIgnoreCase(usuarioDto.getPassword()))
			throw new ServiceException(ErrorCode.INVALID_PASSWORD,"usuario.clave.novalida", usuario);
		
		//se cargan las funcionalidades
		List<FuncionalidadDTO> funcionalidadesList = new ArrayList<FuncionalidadDTO>();
		for(PerfilDTO p: usuarioDto.getPerfilesAsignados()){
			for(FuncionalidadDTO f: p.getFuncAsignadas()){
				funcionalidadesList.add(f);
			}
		}
		usuarioDto.setFuncionalidades(funcionalidadesList);
		
		//se cargan los perfiles no asignados al usuario
		usuarioDto.setPerfilesNoAsignados(this.perfilDAO.listPerfilNoAsignados(usuarioDto.getId()));

		return usuarioDto;
	}


	@Override
	public void deleteUsuario(Long id, InvocationContext ic) throws ServiceException {
		if (id == null || id <= 0)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","id");

		UsuarioDTO usuario =  usuarioDAO.getUsuarioById(id);

		if(usuario == null)
			throw new ServiceException(ErrorCode.NO_DATA_FOUND,"usuario.notfound", id);

		try {
			usuarioDAO.deleteUsuario(usuario);
		}
		catch (DataIntegrityViolationException e){
			throw new ServiceException(ErrorCode.DATA_INTEGRITY_VIOLATION, "usuario.constraint.violation", id);
		}

	}

	@Override
	public UsuarioDTO updateUsuario(Long id, UsuarioDTO dto, InvocationContext ic) throws ServiceException {
		if (id == null || id <= 0)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","id");

		if (null == dto)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","dto");
		
		UsuarioDTO usuario = usuarioDAO.getUsuarioById(id);

		if (usuario == null)
			throw new ServiceException(ErrorCode.NO_DATA_FOUND,"usuario.notfound", id);
		
		//si la clave se envia nula, no se actualiza
		if(usuario.getPassword() != null && !usuario.getPassword().isEmpty()){
			dto.setPassword(encriptador.encriptaEnMD5(dto.getPassword()));
		}
//		dto.setClave(encriptador.encriptaEnMD5(dto.getClaveNueva()));
		if(dto.getName() != null)
			usuario.setName(dto.getName());
		if(dto.getIdEscribano() != null)
			usuario.setIdEscribano(dto.getIdEscribano());
		if(dto.getUsername() != null)
			usuario.setUsername(dto.getUsername());
		if(dto.getEmail() != null)
			usuario.setEmail(dto.getEmail());
		if(dto.getIsTitular() != null)
			usuario.setIsTitular(dto.getIsTitular());
		if(dto.getActivo() != null)
			usuario.setActivo(dto.getActivo());

		Long trn = usuarioDAO.getTrnUsuarios();
		dto.setTrn(trn+1L);
		
		Utils.validarDTO(usuario);
		usuarioDAO.updateUsuario(usuario);
		
		if(dto.getEliminar() != null){
			UsuarioPerfilDTO up = new UsuarioPerfilDTO();
			for(PerfilDTO p: dto.getEliminar().getPerfiles()){
				up.setIdPerfil(p.getId());
				up.setIdUsuario(dto.getId());
				this.usuarioPerfilDAO.deleteUsuarioPerfil(up);
				up = new UsuarioPerfilDTO();
			}
		}
		
		if(dto.getAgregar() != null){
			if(dto.getAgregar().getPerfiles() != null){
				UsuarioPerfilDTO up = new UsuarioPerfilDTO();
				for(PerfilDTO p: dto.getAgregar().getPerfiles()){
					up.setIdPerfil(p.getId());
					up.setIdUsuario(dto.getId());
					//verificar si el usuario ya posee el perfil
					UsuarioPerfilDTO upDTO = this.usuarioPerfilDAO.getUsuarioPerfil(up);
					if(upDTO == null){
						this.usuarioPerfilDAO.createUsuarioPerfil(up);
					}
					up = new UsuarioPerfilDTO();
				}
			}
		}
		
		return usuario;
	}
	@Override
	public UsuarioDTO createUsuario(UsuarioDTO dto, InvocationContext ic) throws ServiceException {
		if (dto == null)
			throw new ServiceException(ErrorCode.PARAMETER_ERROR,"parameter.error.null","dto");

		try {
			Long trn = usuarioDAO.getTrnUsuarios();
			dto.setTrn(trn+1L);
			
			//encriptar clave con MD5
			dto.setPassword(encriptador.encriptaEnMD5(dto.getPassword()));
			
			Utils.validarDTO(dto);
			usuarioDAO.createUsuario(dto);
			//guardar perfiles
			if(dto.getPerfilesAsignados() != null && !dto.getPerfilesAsignados().isEmpty()){
				UsuarioPerfilDTO upDto = new UsuarioPerfilDTO();
				for(PerfilDTO p: dto.getPerfilesAsignados()){
					upDto.setIdUsuario(dto.getId());
					upDto.setIdPerfil(p.getId());
					usuarioPerfilDAO.createUsuarioPerfil(upDto);
					upDto = new UsuarioPerfilDTO();
				}
			}
		}
		catch (DuplicateKeyException e){
			throw new ServiceException(ErrorCode.DUPLICATE_KEY_EXCEPTION, "usuario.duplicate.key");
		}

		return dto;
	}
	
	public UsuarioPerfilDAO getUsuarioPerfilDAO() {
		return usuarioPerfilDAO;
	}

	public void setUsuarioPerfilDAO(UsuarioPerfilDAO usuarioPerfilDAO) {
		this.usuarioPerfilDAO = usuarioPerfilDAO;
	}

	public UsuarioDAO getUsuarioDAO() {
		return usuarioDAO;
	}

	public PerfilDAO getPerfilDAO() {
		return perfilDAO;
	}

	public void setPerfilDAO(PerfilDAO perfilDAO) {
		this.perfilDAO = perfilDAO;
	}

	@Override
	public UsuarioDTO actualizarClave(Long id, UsuarioDTO dto,
			InvocationContext ic) throws ServiceException {
		// TODO Auto-generated method stub
		return null;
	}

}